//! # 框架健康检查实现
//! 
//! 本模块提供了RustCloud框架的健康检查实现。

use crate::framework::traits::*;
use serde::{Serialize, Deserialize};
use std::collections::HashMap;

/// 健康状态
#[derive(Debug, Serialize, Deserialize)]
pub struct HealthStatus {
    pub status: String,
    pub components: HashMap<String, ComponentHealth>,
    pub timestamp: chrono::DateTime<chrono::Utc>,
}

/// 组件健康状态
#[derive(Debug, Serialize, Deserialize)]
pub struct ComponentHealth {
    pub status: String,
    pub details: Option<String>,
}

impl From<crate::framework::traits::HealthStatus> for HealthStatus {
    fn from(status: crate::framework::traits::HealthStatus) -> Self {
        let components = status.components.into_iter().map(|(name, component)| {
            let status_str = match component.level {
                crate::framework::traits::HealthLevel::Healthy => "UP",
                crate::framework::traits::HealthLevel::Warning => "WARNING",
                crate::framework::traits::HealthLevel::Unhealthy => "DOWN",
                crate::framework::traits::HealthLevel::Unknown => "UNKNOWN",
            }.to_string();
            
            (name, ComponentHealth {
                status: status_str,
                details: component.message,
            })
        }).collect();
        
        HealthStatus {
            status: match status.status {
                crate::framework::traits::HealthLevel::Healthy => "UP",
                crate::framework::traits::HealthLevel::Warning => "WARNING",
                crate::framework::traits::HealthLevel::Unhealthy => "DOWN",
                crate::framework::traits::HealthLevel::Unknown => "UNKNOWN",
            }.to_string(),
            components,
            timestamp: chrono::DateTime::<chrono::Utc>::from(status.timestamp),
        }
    }
}

/// 健康检查结果
#[derive(Debug, Serialize, Deserialize)]
pub struct HealthCheckResult {
    /// 健康检查是否通过
    pub healthy: bool,
    /// 健康检查消息
    pub message: Option<String>,
    /// 详细信息
    pub details: HashMap<String, String>,
}

/// 健康检查器trait
#[async_trait::async_trait]
pub trait HealthChecker: Send + Sync {
    /// 执行健康检查
    async fn check_health(&self) -> ServiceResult<HealthCheckResult>;
    
    /// 获取检查器名称
    fn name(&self) -> &str;
}

/// HTTP健康检查器
pub struct HttpHealthChecker {
    url: String,
    client: reqwest::Client,
}

impl HttpHealthChecker {
    pub fn new(url: String) -> Self {
        Self {
            url,
            client: reqwest::Client::new(),
        }
    }
}

#[async_trait::async_trait]
impl HealthChecker for HttpHealthChecker {
    async fn check_health(&self) -> ServiceResult<HealthCheckResult> {
        match self.client.get(&self.url).send().await {
            Ok(response) => {
                let healthy = response.status().is_success();
                Ok(HealthCheckResult {
                    healthy,
                    message: Some(format!("HTTP状态码: {}", response.status())),
                    details: HashMap::new(),
                })
            },
            Err(e) => {
                Ok(HealthCheckResult {
                    healthy: false,
                    message: Some(format!("连接失败: {}", e)),
                    details: HashMap::new(),
                })
            }
        }
    }

    fn name(&self) -> &str {
        "http"
    }
}

/// TCP健康检查器
pub struct TcpHealthChecker {
    address: String,
}

impl TcpHealthChecker {
    pub fn new(address: String) -> Self {
        Self { address }
    }
}

#[async_trait::async_trait]
impl HealthChecker for TcpHealthChecker {
    async fn check_health(&self) -> ServiceResult<HealthCheckResult> {
        match tokio::net::TcpStream::connect(&self.address).await {
            Ok(_) => {
                Ok(HealthCheckResult {
                    healthy: true,
                    message: Some("TCP连接成功".to_string()),
                    details: HashMap::new(),
                })
            },
            Err(e) => {
                Ok(HealthCheckResult {
                    healthy: false,
                    message: Some(format!("TCP连接失败: {}", e)),
                    details: HashMap::new(),
                })
            }
        }
    }

    fn name(&self) -> &str {
        "tcp"
    }
}